using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;

namespace NodeCanvas
{
	public static class EventHandler
	{
		public class SubscribedMember
		{
			public object subscribedObject;

			public Action<object> subscribedFunction;

			public int invokePriority;

			public bool unsubscribeWhenReceive;

			public SubscribedMember(object obj, int invokePriority, bool unsubscribeWhenReceive)
			{
				subscribedObject = obj;
				this.invokePriority = invokePriority;
				this.unsubscribeWhenReceive = unsubscribeWhenReceive;
			}

			public SubscribedMember(Action<object> func, int invokePriority, bool unsubscribeWhenReceive)
			{
				subscribedFunction = func;
				this.invokePriority = invokePriority;
				this.unsubscribeWhenReceive = unsubscribeWhenReceive;
			}
		}

		public static bool logEvents;

		public static Dictionary<string, List<SubscribedMember>> subscribedMembers = new Dictionary<string, List<SubscribedMember>>();

		public static void Subscribe(object obj, Enum eventEnum, int invokePriority = 0, bool unsubscribeWhenReceive = false)
		{
			Subscribe(obj, eventEnum.ToString(), invokePriority, unsubscribeWhenReceive);
		}

		public static void Subscribe(object obj, string eventName, int invokePriority = 0, bool unsubscribeWhenReceive = false)
		{
			MethodInfo methodInfo = obj.GetType().NCGetMethod(eventName, true);
			if (methodInfo == null)
			{
				Debug.LogError("EventHandler: No Method with name '" + eventName + "' exists on '" + obj.GetType().Name + "' Subscribed Type");
				return;
			}
			if (!subscribedMembers.ContainsKey(eventName))
			{
				subscribedMembers[eventName] = new List<SubscribedMember>();
			}
			foreach (SubscribedMember item in subscribedMembers[eventName])
			{
				if (item.subscribedObject == obj)
				{
					Debug.LogWarning(string.Concat("obj ", obj, " is allready subscribed to ", eventName));
					return;
				}
			}
			if (logEvents)
			{
				Debug.Log(string.Concat("@@@ ", obj, " subscribed to ", eventName));
			}
			subscribedMembers[eventName].Add(new SubscribedMember(obj, invokePriority, unsubscribeWhenReceive));
			subscribedMembers[eventName] = subscribedMembers[eventName].OrderBy((SubscribedMember member) => -member.invokePriority).ToList();
		}

		public static void SubscribeFunction(Action<object> func, Enum eventEnum)
		{
			SubscribeFunction(func, eventEnum.ToString());
		}

		public static void SubscribeFunction(Action<object> func, string eventName)
		{
			if (!subscribedMembers.ContainsKey(eventName))
			{
				subscribedMembers[eventName] = new List<SubscribedMember>();
			}
			foreach (SubscribedMember item in subscribedMembers[eventName])
			{
				if (item.subscribedFunction == func)
				{
					if (logEvents)
					{
						Debug.Log("Function allready subscribed to " + eventName);
					}
					return;
				}
			}
			subscribedMembers[eventName].Add(new SubscribedMember(func, 0, false));
		}

		public static void Unsubscribe(object obj)
		{
			if (obj == null)
			{
				return;
			}
			foreach (string key in subscribedMembers.Keys)
			{
				SubscribedMember[] array = subscribedMembers[key].ToArray();
				foreach (SubscribedMember subscribedMember in array)
				{
					if (subscribedMember.subscribedObject == obj)
					{
						subscribedMembers[key].Remove(subscribedMember);
						if (logEvents)
						{
							Debug.Log(string.Concat("XXX ", obj, "Unsubscribed from everything!"));
						}
					}
				}
			}
		}

		public static void Unsubscribe(object obj, Enum eventEnum)
		{
			Unsubscribe(obj, eventEnum.ToString());
		}

		public static void Unsubscribe(object obj, string eventName)
		{
			if (obj == null || !subscribedMembers.ContainsKey(eventName))
			{
				return;
			}
			SubscribedMember[] array = subscribedMembers[eventName].ToArray();
			foreach (SubscribedMember subscribedMember in array)
			{
				if (subscribedMember.subscribedObject == obj)
				{
					subscribedMembers[eventName].Remove(subscribedMember);
					if (logEvents)
					{
						Debug.Log(string.Concat("XXX Member ", obj, " Unsubscribed from ", eventName));
					}
					return;
				}
			}
			if (logEvents)
			{
				Debug.Log(string.Concat("You tried to Unsubscribe ", obj, " from ", eventName, ", but it was never subscribed there!"));
			}
		}

		public static void UnsubscribeFunction(Action<object> func)
		{
			if (func == null)
			{
				return;
			}
			foreach (string key in subscribedMembers.Keys)
			{
				SubscribedMember[] array = subscribedMembers[key].ToArray();
				foreach (SubscribedMember subscribedMember in array)
				{
					if (subscribedMember.subscribedFunction != null && subscribedMember.subscribedFunction.ToString() == func.ToString())
					{
						subscribedMembers[key].Remove(subscribedMember);
					}
				}
			}
			if (logEvents)
			{
				Debug.Log("XXX " + func.ToString() + " Unsubscribed from everything");
			}
		}

		public static bool Dispatch(Enum eventEnum, object arg = null)
		{
			return Dispatch(eventEnum.ToString(), arg);
		}

		public static bool Dispatch(string eventName, object arg = null)
		{
			if (logEvents)
			{
				Debug.Log(">>> Event " + eventName + " Dispatched. (" + ((arg == null) ? string.Empty : arg.GetType().Name) + ") Argument");
			}
			if (!subscribedMembers.ContainsKey(eventName))
			{
				Debug.LogWarning("EventHandler: Event '" + eventName + "' was not received by anyone!");
				return false;
			}
			SubscribedMember[] array = subscribedMembers[eventName].ToArray();
			foreach (SubscribedMember subscribedMember in array)
			{
				object subscribedObject = subscribedMember.subscribedObject;
				if (subscribedObject == null && subscribedMember.subscribedFunction == null)
				{
					subscribedMembers[eventName].Remove(subscribedMember);
					continue;
				}
				if (logEvents)
				{
					Debug.Log("<<< Event " + eventName + " Received by " + subscribedObject);
				}
				if (subscribedMember.unsubscribeWhenReceive)
				{
					Unsubscribe(subscribedObject, eventName);
				}
				if (subscribedMember.subscribedFunction != null)
				{
					subscribedMember.subscribedFunction(arg);
					continue;
				}
				MethodInfo methodInfo = subscribedObject.GetType().NCGetMethod(eventName, true);
				if (methodInfo == null)
				{
					Debug.LogWarning(string.Concat("Method '", eventName, "' not found on subscribed object '", subscribedObject, "'"));
					continue;
				}
				ParameterInfo[] parameters = methodInfo.GetParameters();
				if (parameters.Length > 1)
				{
					Debug.LogError(string.Concat("Subscribed function to call '", methodInfo.Name, "' has more than one parameter on ", subscribedObject, ". It should only have one."));
				}
				else
				{
					object[] parameters2 = ((parameters.Length != 1) ? null : new object[1] { arg });
					if (methodInfo.ReturnType == typeof(IEnumerator))
					{
						MonoManager.current.StartCoroutine((IEnumerator)methodInfo.Invoke(subscribedObject, parameters2));
					}
					else
					{
						methodInfo.Invoke(subscribedObject, parameters2);
					}
				}
			}
			return true;
		}
	}
}
